﻿using System.Collections.ObjectModel;
using nRoute.Components;
using nRoute.Samples.SquareAway.Model;
using nRoute.ViewModels;
using nRoute.Components.Composition;
using System;
using System.Windows.Threading;
using nRoute.Samples.SquareAway.Services;

namespace nRoute.Samples.SquareAway.ViewModels
{
    [MapViewModel(typeof(MainPage))]
    public class MainPageViewModel 
        : ViewModelBase
    {
        private const string GAME_OVER_FORMAT = "Game Over.\nYour Score was {0}.";
        private const string GAME_OVER_NEW_HIGH_FORMAT = "Game Over.\nYour Score was {0}.\nNEW High Score.";
        private const string GAME_OVER_HIGHEST_SCORE_FORMAT = "Game Over.\nYour Score was {0}.\nHighest Score is {1}.";
        private const string GAME_PAUSED = "Game Paused.\nPress Play to Resume.";
        private const string GAME_START = "Press Play to Start.\nUse the Back Button to Pause the Game.";

        private Engine _engine;
        private IHighScoreService _scoreService;

        [ResolveConstructor]
        public MainPageViewModel(Engine engine, IHighScoreService scoreService)
        {
            if (engine == null) throw new ArgumentNullException("engine");
            if (scoreService == null) throw new ArgumentNullException("scoreService");

            _scoreService = scoreService;
            _engine = engine;
            _engine.NewGame(7, 10, OnGameCompleted);

            SetupCommands();

            this.Message = GAME_START;
            this.PlayState = ViewModels.PlayState.Paused;
        }

#region Properties

        public int Score
        {
            get { return _engine.Score; }
        }

        public ReadOnlyObservableCollection<Square> Squares
        {
            get { return _engine.Squares; }
        }

        public ActionCommand<Square> HighlightCommand { get; private set; }

        public ActionCommand<Square> UnHighlightCommand { get; private set; }

        public ActionCommand<Square> HideCommand { get; private set; }

        public ActionCommand TogglePlayStateCommand { get; private set; }

        public PlayState PlayState { get; private set; }

        public string Message { get; private set; }

#endregion

#region Helpers

        private void SetupCommands()
        {
            HighlightCommand = new ActionCommand<Square>((b) =>  _engine.HighlightSquare(b));

            UnHighlightCommand = new ActionCommand<Square>((b) =>  _engine.UnHighlightSquare(b));

            HideCommand = new ActionCommand<Square>((b) => 
            {
                var _score = _engine.Score;
                _engine.HideSquare(b);
                if (_score != _engine.Score) NotifyPropertyChanged(() => Score);
            });

            TogglePlayStateCommand = new ActionCommand(() => 
            {
                if (PlayState == ViewModels.PlayState.Completed)
                {                     
                    PlayState = PlayState.Started;
                    NotifyPropertyChanged(() => PlayState);
                }
                else if (PlayState == ViewModels.PlayState.Started)
                {
                    Message = GAME_PAUSED;
                    NotifyPropertyChanged(() => Message);

                    PlayState = PlayState.Paused;
                    NotifyPropertyChanged(() => PlayState);
                }
                else if (PlayState == ViewModels.PlayState.Paused)
                {
                    PlayState = PlayState.Started;
                    NotifyPropertyChanged(() => PlayState);
                }
            });
        }

        private void OnGameCompleted()
        {
            PlayState = PlayState.Completed;
            NotifyPropertyChanged(() => PlayState);

            _scoreService.RegisterLastScore(_engine.Score);
            var _highestScore = _scoreService.GetHighestScore();

            Message = GetScoreMessage(_highestScore);
            NotifyPropertyChanged(() => Message);

            // this enables running the post-completion animation before we overrun it with changes
            DispatcherSynchronizationContext.Current.Post((s) =>
            {
                _engine.NewGame(7, 10, OnGameCompleted);
                NotifyPropertyChanged(() => Score);
            }, null);
        }

        private string GetScoreMessage(int? highestScore)
        {
            if (highestScore.HasValue && highestScore.Value == _engine.Score)
            {
                return string.Format(GAME_OVER_NEW_HIGH_FORMAT, _engine.Score);
            }
            else if (highestScore.HasValue)
            {
                return string.Format(GAME_OVER_HIGHEST_SCORE_FORMAT, _engine.Score, highestScore.Value);
            }
            else
            {
                return string.Format(GAME_OVER_FORMAT, _engine.Score);
            }
        }

#endregion

    }
}